package com.wish.datastructure;

import lombok.AllArgsConstructor;
import lombok.ToString;
/**
 * Created by suliucheng on 2021/4/1 20:56
 * Directions:
 */

/**
 * 链表类：用于管理节点类   每一个节点都会推向节点的后一位
 * 单链表（新加的元素都在最后一个节点）小结：
 * 每个节点看做是一个对象DemoNode，每一个DemoNode对象中都有属性 head：String,data:Object,next:DemoNode
 * 即意思为：每个节点都包含：头信息，数据信息，下一个节点的地址
 * 一个单链表对象需要组合一个头结点，头结点是直接初始化好的，并设定好默认值
 * 单链表对象至少需要提供add()方法和show()方法
 * add:新增的时候只考虑在下一个节点地址为空的节点中（下一个节点为null则可以判定该节点为尾结点）,将当前节点赋值给next:DemoNode
 * show:查看链表的时候，一直打印next节点，直到一个空的next
 * modify:要求传入的头编号不能改
 * delete:要求传入的头编号不能改
 * 技巧：临时节点
 */
public class SingleLinkedList {
    /**
     * 测试部分
     */
    public static void main(String[] args) {
        Information slc = new Information("苏刘成", "java程序员");
        HeroNode nodeOne = new HeroNode(1, slc);

        Information wj = new Information("吴炬", "java程序员");
        HeroNode nodeTwo = new HeroNode(3, wj);

        Information mht = new Information("马化腾", "腾讯公司CEO");
        HeroNode nodeThree = new HeroNode(2, mht);
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        System.out.println("将每个节点添加到链表最后一个位置：");
        singleLinkedList.add(nodeOne);
        singleLinkedList.add(nodeTwo);
        singleLinkedList.add(nodeThree);
        singleLinkedList.show();
        System.out.println("修改节点信息“马化腾”为“雷军”：");
        Information lj = new Information("雷军", "小米公司CEO");
        HeroNode nodeThreeModify = new HeroNode(2, lj);
        singleLinkedList.modify(nodeThreeModify);
        singleLinkedList.show();
        System.out.println("删除节点信息“雷军”：");
        singleLinkedList.delete(nodeThreeModify);
//        System.out.println("删除节点信息“苏刘成”：");
//        singleLinkedList.delete(nodeOne);
//        System.out.println("删除节点信息“吴炬”：");
//        singleLinkedList.delete(nodeTwo);
//        System.out.println("将每个节点按照头结点排序添加到链表中：");
//        singleLinkedList.addByHead(nodeOne);
//        singleLinkedList.addByHead(nodeTwo);
//        singleLinkedList.addByHead(nodeThree);
        singleLinkedList.show();
    }

    /**
     * 链表必然会有一个头节点，这个节点不动
     */
    private static HeroNode headNode = new HeroNode(0, new Information("default", "default"));

    /**
     * 根据传入的节点头信息删除当前链表的该节点
     *
     * @param heroNode
     */
    public static void delete(HeroNode heroNode) {
        HeroNode temp = headNode;
        while (true) {
            if (temp.next.head == heroNode.head) {
                break;
            } else if (temp.next == null) {
                throw new RuntimeException("删除异常：该队列中不存在与参数相同的节点。");
            }
            temp = temp.next;
        }
        temp.next = heroNode.next;
    }

    /**
     * 根据传入的节点头信息修改该信息的data:object
     *
     * @param heroNode 修改的节点
     */
    public static void modify(HeroNode heroNode) {
        HeroNode temp = headNode;
        while (true) {
            if (temp.head == heroNode.head) {
                break;
            } else if (temp.next == null) {
                throw new RuntimeException("修改操作异常，该链表中不存在相同头信息的节点。");
            }
            temp = temp.next;
        }
        temp.information = heroNode.information;
    }

    /**
     * 根据节点的头信息排序add
     *
     * @param heroNode 新加的节点对象
     */
    public static void addByHead(HeroNode heroNode) {
        /**
         * 当且仅当新加的节点头小于后一个,大于前一个的时候，就把该节点插入 如果存在同样大小的头结点则给出提示，并且添加失败
         */
        HeroNode temp = headNode;
        while (true) {
            if (temp.next == null) {
                break;
            } else if (temp.next.head > heroNode.head) {
                break;
            } else if (temp.next.head == heroNode.head) {
                throw new RuntimeException("存在相同节点，元素添加失败！");
            }
            temp = temp.next;
        }
        heroNode.next = temp.next;
        temp.next = heroNode;
    }

    /**
     * 默认add，只把每一个节点都放在链表的最后一个位置 jdk:LinkedList
     *
     * @param heroNode 新加的节点对象
     */
    public static void add(HeroNode heroNode) {
        /**
         * 最后一个节点的next必定为空，新加的节点给next
         */
        HeroNode temp = headNode;
        while (true) {
            /**
             * temp假想是一个指针
             * 找到最后一个节点，并且把新的节点给 next
             * 打破循环的条件:最后一个节点的next为空
             * 否则：temp = temp.next;
             */
            if (temp.next == null) {
                break;
            }
            temp = temp.next;
        }
        temp.next = heroNode;
    }

    /**
     * 显示链表
     */
    public void show() {
        if (headNode.next == null) {
            System.out.println("链表为空");
            return;
        }
        HeroNode temp = headNode.next;
        while (true) {
            if (temp == null) {
                break;
            }
            //输出节点信息
            System.out.println(temp);
            //temp后移
            temp = temp.next;
        }
    }

    /**
     * 节点类
     */
    static
    class HeroNode {
        private Integer head;
        private Information information;
        private HeroNode next = null;

        public HeroNode(Integer head, Information information) {
            this.head = head;
            this.information = information;
        }

        @Override
        public String toString() {
            return "HeroNode{" +
                    "head='" + head + '\'' +
                    ", information=" + information +
                    '}';
        }
    }

    /**
     * 作为信息载体
     */
    @ToString
    @AllArgsConstructor
    static
    class Information {
        private String name;
        private String job;
    }
}


